using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Google.Protobuf;
using UnityEngine.SocialPlatforms;

public class NetPacket
{
    private const int buffer_size = 1024;
    public byte[] buffer = new byte[buffer_size];
    private byte[] tempBuffer = null;//接受到很大的消息的时候用
    private bool isUsingTempBuf = false;//标识当前tempBuffer有在被使用

    private int _start = 0;
    public int Remain => buffer.Length - _start;
    public int Start => _start;

    public void UnpackMessage(int msgLen, Action<byte, byte[]> OperationRequest)
    {
        //message type: len(4) msgId(1) data(x)
        //message: <length> 1 username=123|password=123
        _start += msgLen;
        while (true)
        {
            if (_start <= 4)
            {
                return;
            }

            int totalLen = BitConverter.ToInt32(buffer, 0);//获取前四个字节（记录着当前这一条tcp消息的总长度
                                                        //Console.WriteLine("totalLen: " + totalLen);
            if (_start >= totalLen) // 消息长度小于等于buffer_size，完整的消息，但可能粘包
            {
                //0-3 length; 4 msgId; 5-x data
                int dataLen = totalLen - 5;
                byte msgId = buffer[4];
                byte[] data = new byte[dataLen];
                Array.Copy(buffer, 5, data, 0, dataLen);
                OperationRequest(msgId, data);

                Array.Copy(buffer, totalLen, buffer, 0, _start - totalLen);//最前面的消息被处理完了，把后面消息挪到最前面
                _start -= totalLen;

                if (isUsingTempBuf)
                {
                    buffer = new byte[buffer_size];
                    tempBuffer = null;
                    isUsingTempBuf = false;
                }
            }
            else//这个消息被分割了，是不完整的
            {
                if (totalLen > buffer_size)//这个消息太大了，比缓冲还大。扩容
                {
                    tempBuffer = new byte[totalLen];
                    Array.Copy(buffer, tempBuffer, buffer.Length);//将buffer中的数据全部转移到tempBuffer中
                    buffer = tempBuffer;//暂时给buffer扩容，其大小等于消息的大小

                    //将这个标识符置位，目的：当下次接受并处理消息完毕时，复原buffer的大小
                    isUsingTempBuf = true;
                }
                break;
            }
        }
    }

    public static byte[] PackMessage(NetMsgID msgId, IMessage message)
    {
        byte byteMsgId = (byte)msgId;
        byte[] respCode_bytes = new byte[1] { byteMsgId };
        byte[] parameter_bytes = message == null ? new byte[0] : Serialize(message);
        byte[] data = respCode_bytes.Concat(parameter_bytes).ToArray();

        int totalLen = data.Length + 4;
        byte[] len_bytes = BitConverter.GetBytes(totalLen);
        byte[] res = len_bytes.Concat(data).ToArray();
        return res;
    }

    public static byte[] Serialize(IMessage message)
    {
        return message.ToByteArray();
    }

    public static T Deserialize<T>(byte[] bytes) where T : IMessage<T>, new()
    {
        
        MessageParser<T> messageParser = new MessageParser<T>(() => { return new T(); });
        return messageParser.ParseFrom(bytes);
    }


    public static string DictionaryToString(Dictionary<byte, object> dict)
    {
        string str = "";
        foreach (byte key in dict.Keys)
        {
            str += (key + "=" + dict[key]);
            str += "|";
        }
        str = str.Substring(0, str.Length - 1);
        return str;
    }
    public static string DictionaryToString(Dictionary<string, object> dict)
    {
        string str = "";
        foreach (string key in dict.Keys)
        {
            str += (key + "=" + dict[key]);
            str += "|";
        }
        str = str.Substring(0, str.Length - 1);
        return str;
    }

    public static Dictionary<string, object> StringToDictionary(string value)
    {
        if (value.Length < 1)
        {
            return null;
        }
        Dictionary<string, object> dic = new Dictionary<string, object>();

        string[] dicStrs = value.Split('|');
        foreach (string str in dicStrs)
        {
            string[] strs = str.Split('=');
            dic.Add(strs[0], strs[1]);
        }
        return dic;
    }
}

public enum NetProtocal { 
    TCP,
    UDP
}


